#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    sweepWidget = new SweepWidget(this);
    ui->SweepWidgetLayout->addWidget(sweepWidget);
    ui->advanced_box->hide();
    connect(ui->loadPoly_bt , SIGNAL(clicked()) , SLOT(choosePolyFile()));
    connect(ui->normals_check , SIGNAL(stateChanged(int)) , SLOT(showNormals(int)));
    connect(ui->resetCam_bt , SIGNAL(clicked()) , SLOT(resetCam()));

    //connecting spin_boxes
    signalMapper = new QSignalMapper(this);

    QList<QDoubleSpinBox *> spinBoxes = this->findChildren<QDoubleSpinBox *>(QRegExp("*_spin" ,Qt::CaseSensitive , QRegExp::Wildcard));
    while(!spinBoxes.empty()){
        QDoubleSpinBox *spinBox = spinBoxes.takeFirst();
        connect(spinBox , SIGNAL(valueChanged(double)) , signalMapper , SLOT(map()));
        signalMapper->setMapping(spinBox , spinBox);
    }

    connect(signalMapper , SIGNAL(mapped(QWidget*)) , this , SLOT(spinBoxChanged(QWidget*)));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::initGLUserInterface(){
    QPair<QString , GLenum> components[] = {QPair<QString , GLenum>(QString("AmbientL_spin") , GL_AMBIENT),
                                            QPair<QString , GLenum>(QString("DifuseL_spin") , GL_DIFFUSE),
                                            QPair<QString , GLenum>(QString("SpecL_spin") , GL_SPECULAR),
                                            QPair<QString , GLenum>(QString("AmbientM_spin") , GL_AMBIENT),
                                            QPair<QString , GLenum>(QString("DifuseM_spin") , GL_DIFFUSE),
                                            QPair<QString , GLenum>(QString("SpecM_spin") , GL_SPECULAR),
                                            QPair<QString , GLenum>(QString("EmissionM_spin") , GL_EMISSION)};

    for(int i = 0 ; i < 7 ; i++){
        initGLComponent(components[i]);
    }

    float shininess;

    glGetMaterialfv(GL_FRONT , GL_SHININESS , &shininess);
    ui->shininessM_spin->setValue(shininess);

    GLboolean enabled;

    glGetBooleanv(GL_LIGHT_MODEL_LOCAL_VIEWER , &enabled);
    ui->modelLocalViewer_check->setChecked(enabled);

    glGetBooleanv(GL_LIGHT_MODEL_TWO_SIDE , &enabled);
    ui->modelTwoSide_check->setChecked(enabled);

    glGetBooleanv(GL_POLYGON_SMOOTH , &enabled);
    ui->polySmooth_check->setChecked(enabled);

    glGetBooleanv(GL_LINE_SMOOTH , &enabled);
    ui->lineSmooth_check->setChecked(enabled);
}

void MainWindow::initGLComponent(QPair<QString , GLenum> component){
    float params[4];
    QDoubleSpinBox *spinB;

    if(component.first.contains("L_spin" , Qt::CaseInsensitive)){
        glGetLightfv(GL_LIGHT0 , component.second , params);
    }
    else{
        glGetMaterialfv(GL_FRONT , component.second , params);
    }

    char prefixes[] = {'r' , 'g' , 'b' , 'a'};

    for(int i = 0 ; i < 4 ; i++){
        spinB = this->findChild<QDoubleSpinBox *>(prefixes[i] + component.first);
        if(spinB != 0){
            spinB->setValue(params[i]);
        }
    }
}

void MainWindow::spinBoxChanged(QWidget *modifiedComponent){
    QDoubleSpinBox *spinBox;
    //QCheckBox *checkBox;

    GLenum pName;
    float params[4];
    QString name = modifiedComponent->objectName();

    if(spinBox = qobject_cast<QDoubleSpinBox *>(modifiedComponent)){
        if(name.contains("Ambient")){
            pName = GL_AMBIENT;
        }
        else{
            if(name.contains("Difuse")){
                pName = GL_DIFFUSE;
            }
            else{
                if(name.contains("Spec")){
                    pName = GL_SPECULAR;
                }
                else{
                    if(name.contains("Emission")){
                        pName = GL_EMISSION;
                    }
                    else{
                        if(name.contains("shininess")){
                            pName = GL_SHININESS;
                        }
                    }
                }
            }
        }

        if(name.contains("L_spin")){
            glGetLightfv(GL_LIGHT0 , pName , params);
        }
        else{
            glGetMaterialfv(GL_FRONT , pName , params);
        }

        switch(name.at(0).toAscii()){
            case 'r': params[0] = spinBox->value(); break;
            case 'g': params[1] = spinBox->value(); break;
            case 'b': params[2] = spinBox->value(); break;
            case 'a': params[3] = spinBox->value(); break;
            default:  params[0] = spinBox->value(); break;
        }

        if(name.contains("L_spin")){
            glLightfv(GL_LIGHT0 , pName , params);
        }
        else{
            glMaterialfv(GL_FRONT , pName , params);
        }
    }
    this->sweepWidget->updateGL();
}

void MainWindow::on_modelTwoSide_check_toggled(bool checked){
    if(checked){
        glLightModeli(GL_LIGHT_MODEL_TWO_SIDE , GL_TRUE);
    }
    else{
        glLightModeli(GL_LIGHT_MODEL_TWO_SIDE , GL_FALSE);
    }
    this->sweepWidget->updateGL();
}

void MainWindow::on_modelLocalViewer_check_toggled(bool checked){
    if(checked){
        glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER , GL_TRUE);
    }
    else{
        glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER , GL_FALSE);
    }
    this->sweepWidget->updateGL();
}

void MainWindow::on_polySmooth_check_toggled(bool checked){

    if(checked){
        glEnable(GL_POLYGON_SMOOTH);
    }
    else{
        glEnable(GL_POLYGON_SMOOTH);
    }
    this->sweepWidget->updateGL();
}

void MainWindow::on_lineSmooth_check_toggled(bool checked){

    if(checked){
        glEnable(GL_LINE_SMOOTH);
    }
    else{
        glEnable(GL_LINE_SMOOTH);
    }
    this->sweepWidget->updateGL();
}

void MainWindow::choosePolyFile(){
    QString fileName;

    fileName = QFileDialog::getOpenFileName(this, "Select the poly file", "../", "Sweep poly files (*.swp)");
    if(!fileName.isNull()){
        this->sweepWidget->poly = this->sweepWidget->readPoly(fileName);
    }

    this->sweepWidget->updateGL();
}

void MainWindow::showNormals(int state){
    if(state == Qt::Checked){
        this->sweepWidget->showNormals = true;
    }
    else{
        this->sweepWidget->showNormals = false;
    }

    this->sweepWidget->updateGL();
}

void MainWindow::resetCam(){
    this->sweepWidget->resetCam();
}
